package com.auto.api.core.type;

import com.auto.api.core.constants.MappingConstants;
import com.auto.api.core.entity.ParseTypeContext;
import com.auto.api.core.entity.ProcessProp;
import com.auto.api.core.entity.PropertyContext;
import com.auto.api.core.util.BeanUtil;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;

/**
 * @program:
 * @description: Class类型转换抽象类
 * @author: liangshf
 * @create: 2020-09-24
 */
public abstract class AbstractParseBeanHandler<Q extends ParseTypeContext<R>, R> implements ParseBeanHandler<Q, R> {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public R getResult(Q parseTypeContext) {
        //前置处理
        if(!beforeParse(parseTypeContext)) return parseTypeContext.getResult();
        //解析属性获取结果集
        parseProps(parseTypeContext);
        return parseTypeContext.getResult();
    }

    private void parseProps(Q context) {
        for (PropertyDescriptor prop : context.getProps()) {
            PropertyContext propertyContext = buildPropertyContext(context, prop);
            if (propertyContext.getPropResType().hasGenerics()) {
                doGenProp(context, propertyContext);
            } else {
                doProp(context, propertyContext);
            }
        }
    }

    /**
     * 解析非泛型Class,或者父类 字段属性
     *
     * @param context Q
     * @param propertyContext PropertyContext
     */
    private void doProp(Q context, PropertyContext propertyContext) {
        if (context.getResolvableType().resolve().getSimpleName().equals(propertyContext.getPropSimpleType())) {
            return;
        }
        processProp(getProcessProp(context, propertyContext));
    }

    /**
     * 解析泛型Class 字段属性
     *
     * @param context Q
     * @param propertyContext PropertyContext
     */
    private void doGenProp(Q context, PropertyContext propertyContext) {
        if (MappingConstants.CLASS
            .equals(BeanUtil.captureName(propertyContext.getPropResType().resolve().getSimpleName()))) {
            return;
        }
        // 返回表示此类型实际类型参数的 Type 对象的数组。
        ResolvableType fieldType = propertyContext.getPropResType();
        ProcessProp<Q> processProp = getProcessProp(context, propertyContext);
        for(int i=0 ; i < fieldType.getGenerics().length ; i++) {
            ResolvableType fieldGenType = fieldType.getGenerics()[i];
            if (fieldGenType.resolve().getSimpleName().equals(context.getSimpleClassName())) {
                continue;
            }
            propertyContext.setGenPropResType(fieldGenType);
            //setGenPropResType根据泛型类型判断
            processProp.setPropType(propertyContext.getJudgePropType());
            //多个继承泛型替换
            processProp(processProp);
        }
    }

    /**
     * 获取属性解析上下文
     * @param context
     * @param propertyContext
     * @return
     */
    public abstract ProcessProp<Q> getProcessProp(Q context, PropertyContext propertyContext);

    private PropertyContext buildPropertyContext(Q context, PropertyDescriptor prop) {
        PropertyContext propertyContext = new PropertyContext();
        propertyContext.setClassResType(context.getResolvableType());
        propertyContext.setProp(prop);
        Field field = ReflectionUtils.findField(context.getClazz(), prop.getName());
        if (field == null) {
            propertyContext.setPropResType(ResolvableType.forClass(Integer.class));
        } else {
            propertyContext.setPropResType(ResolvableType.forField(field, context.getResolvableType()));
        }

        if (propertyContext.getClassResType().resolve() == null || propertyContext.getPropResType().resolve() == null) {
            propertyContext.setPropType(MappingConstants.INT);
            propertyContext.setPropGenType(MappingConstants.INT);
            propertyContext.setPropSimpleType(MappingConstants.INT);
            propertyContext.setPropSimpleGenType(MappingConstants.INT);
        } else {
            propertyContext.setPropType(propertyContext.getPropResType().resolve().getName());
            propertyContext.setPropSimpleType(propertyContext.getPropResType().resolve().getSimpleName());
        }
        return propertyContext;
    }

    /**
     * 前置处理
     *
     * @param parseTypeContext Q
     */
    public abstract Boolean beforeParse(Q parseTypeContext);

    /**
     * 处理属性解析
     * @param processProp ProcessProp<Q>
     */
    public abstract void processProp(ProcessProp<Q> processProp);
}
